package com.ruoyi.drawing.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.constant.DrawingConstants;
import com.ruoyi.common.core.utils.BeanCopyUtils;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.drawing.api.params.DrawingModelDocumentParams;
import com.ruoyi.drawing.api.query.DrawingModelDocumentQuery;
import com.ruoyi.drawing.api.vo.DrawingModelDocumentVO;
import com.ruoyi.drawing.api.vo.FileVO;
import com.ruoyi.drawing.api.vo.RegionDownloadsUploadsVO;
import com.ruoyi.drawing.api.vo.StorageModelQuantityVO;
import com.ruoyi.drawing.domain.DtsDrawingModelDocument;
import com.ruoyi.drawing.domain.DtsDrawingModelDocumentHistory;
import com.ruoyi.drawing.domain.DtsDrawingModelRegion;
import com.ruoyi.drawing.domain.DtsFile;
import com.ruoyi.drawing.mapper.DtsDrawingModelDocumentMapper;
import com.ruoyi.drawing.service.IDtsDrawingModelDocumentHistoryService;
import com.ruoyi.drawing.service.IDtsDrawingModelDocumentService;
import com.ruoyi.drawing.service.IDtsDrawingModelRegionService;
import com.ruoyi.drawing.service.IDtsFileService;
import io.jsonwebtoken.lang.Assert;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * 图档中心模型文档Service业务层处理
 *
 * @author ZhangYu
 * @date 2024-04-30
 */
@Slf4j
@Service
public class DtsDrawingModelDocumentServiceImpl extends ServiceImpl<DtsDrawingModelDocumentMapper, DtsDrawingModelDocument> implements IDtsDrawingModelDocumentService {

    @Resource
    private IDtsFileService fileService;
    @Resource
    private IDtsDrawingModelRegionService drawingModelRegionService;
    @Resource
    private RedisService redisService;
    @Resource
    private IDtsDrawingModelDocumentHistoryService drawingModelDocumentHistoryService;

    /**
     * 编码前缀
     */
    private static final String DOCUMENT_CODE_PREFIX = "DOCUMENT_CODE_";

    @Override
    public Page<DrawingModelDocumentVO> drawingModelDocumentPage(DrawingModelDocumentQuery drawingModelDocumentQuery) {
        return baseMapper.drawingModelDocumentPage(new Page<>(drawingModelDocumentQuery.getPageNum(), drawingModelDocumentQuery.getPageSize()), drawingModelDocumentQuery);
    }

    @Override
    public Page<FileVO> filePageByCode(Integer pageNum, Integer pageSize, String documentCode) {
        return baseMapper.selectFilePageByDocumentCode(new Page<>(pageNum, pageSize), documentCode);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addDrawingModelDocument(DrawingModelDocumentParams drawingModelDocumentParams) {
        String documentCode = createDocumentCode();
        String versionNumber = String.valueOf(createVersionNumber(documentCode));
        DtsDrawingModelDocument drawingModelDocument = BeanCopyUtils.copyNewBean(drawingModelDocumentParams, DtsDrawingModelDocument.class);
        drawingModelDocument.setId(IdWorker.getId());
        drawingModelDocument.setDocumentCode(documentCode);
        drawingModelDocument.setVersionNumber(versionNumber);
        baseMapper.insert(drawingModelDocument);
        fileService.addFileList(drawingModelDocumentParams.getFileList(), drawingModelDocument.getId(), DrawingConstants.TABLE_NAME_DTS_DRAWING_MODEL_DOCUMENT);
    }

    /**
     * 创建图档编码 如：DOCUMENT_CODE_00001
     *
     * @return 图档编码
     */
    private synchronized String createDocumentCode() {
        String key = DrawingConstants.DOCUMENT_CODE_KEY;
        if (redisService.hasKey(key)) {
            log.info("--------------------------------------------------------------------------------图档编码存在redis中");
            Integer number = redisService.getCacheObject(key);
            redisService.setCacheObject(key, ++number, DrawingConstants.EXPIRATION_TIME, TimeUnit.MINUTES);
            return DOCUMENT_CODE_PREFIX + String.format("%05d", number);
        }
        String maxDocumentCode = baseMapper.getMaxDocumentCode();
        if (StrUtil.isNotEmpty(maxDocumentCode)) {
            log.info("--------------------------------------------------------------------------------图档编码存在数据库中");
            String oldNumber = maxDocumentCode.substring(maxDocumentCode.length() - 5);
            int newNumber = Integer.parseInt(oldNumber);
            redisService.setCacheObject(key, ++newNumber, DrawingConstants.EXPIRATION_TIME, TimeUnit.MINUTES);
            return DOCUMENT_CODE_PREFIX + String.format("%05d", newNumber);
        }
        log.info("----------------------------------------------------------------------------图档编码数据库、redis都不存在");
        redisService.setCacheObject(key, 1, DrawingConstants.EXPIRATION_TIME, TimeUnit.MINUTES);
        return DOCUMENT_CODE_PREFIX + String.format("%05d", 1);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDrawingModelDocument(DrawingModelDocumentParams drawingModelDocumentParams) {
        //历史数据
        DtsDrawingModelDocument oldDrawingModelDocument = baseMapper.selectById(drawingModelDocumentParams.getId());
        Assert.notNull(oldDrawingModelDocument, "此信息不存在");
        DtsDrawingModelDocumentHistory drawingModelDocumentHistory = BeanUtil.copyProperties(oldDrawingModelDocument, DtsDrawingModelDocumentHistory.class);
        //保存历史记录。删除原数据，添加新数据。原文件信息不删，会用文档（历史记录和新数据）的id联查相关文件信息
        DtsDrawingModelDocument drawingModelDocument = BeanCopyUtils.copyNewBean(drawingModelDocumentParams, DtsDrawingModelDocument.class);
        drawingModelDocument.setId(IdWorker.getId());
        drawingModelDocument.setVersionNumber(String.valueOf(createVersionNumber(oldDrawingModelDocument.getDocumentCode())));
        drawingModelDocument.setDocumentCode(oldDrawingModelDocument.getDocumentCode());
        drawingModelDocumentHistoryService.save(drawingModelDocumentHistory);
        baseMapper.deleteById(drawingModelDocumentParams.getId());
        baseMapper.insert(drawingModelDocument);
        fileService.addFileList(drawingModelDocumentParams.getFileList(), drawingModelDocument.getId(), DrawingConstants.TABLE_NAME_DTS_DRAWING_MODEL_DOCUMENT);
    }

    /**
     * 创建版本号
     *
     * @param documentCode 文档编码
     * @return 版本号
     */
    private synchronized int createVersionNumber(String documentCode) {
        String key = DrawingConstants.VERSION_NUMBER_KEY;
        if (redisService.hasKey(key)) {
            log.info("------------------------------------------------------------------------------版本号key存在redis中");
            //若不存在文档编码版本号则赋默认值：0
            int versionNumber = (int) Optional.ofNullable(redisService.getCacheMapValue(key, documentCode)).orElse(DrawingConstants.DRAWING_MODEL_DOCUMENT_VERSION_NUMBER_ZERO);
            redisService.setCacheMapValue(key, documentCode, ++versionNumber);
            redisService.expire(key, DrawingConstants.EXPIRATION_TIME, TimeUnit.MINUTES);
            return versionNumber;
        }
        DtsDrawingModelDocument oldDrawingModelDocument = baseMapper.selectOne(new QueryWrapper<DtsDrawingModelDocument>().lambda().eq(DtsDrawingModelDocument::getDocumentCode, documentCode));
        if (ObjectUtil.isNotEmpty(oldDrawingModelDocument)) {
            log.info("---------------------------------------------------------------------------------版本号存在数据库中");
            int versionNumber = Integer.parseInt(oldDrawingModelDocument.getVersionNumber());
            redisService.setCacheMapValue(key, documentCode, ++versionNumber);
            redisService.expire(key, DrawingConstants.EXPIRATION_TIME, TimeUnit.MINUTES);
            return versionNumber;
        }
        log.info("-----------------------------------------------------------------------------版本号数据库、redis都不存在");
        redisService.setCacheMapValue(key, documentCode, DrawingConstants.DRAWING_MODEL_DOCUMENT_VERSION_NUMBER_ONE);
        redisService.expire(key, DrawingConstants.EXPIRATION_TIME, TimeUnit.MINUTES);
        return DrawingConstants.DRAWING_MODEL_DOCUMENT_VERSION_NUMBER_ONE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeDrawingModelDocument(Long id) {
        //查询相关编码的历史数据id（包含本id）
        List<Long> idList = baseMapper.selectIdListByDocumentId(id);
        baseMapper.deleteById(id);
        fileService.remove(new QueryWrapper<DtsFile>().lambda()
                .in(DtsFile::getConnectTableId, idList)
                .eq(DtsFile::getTableName, DrawingConstants.TABLE_NAME_DTS_DRAWING_MODEL_DOCUMENT)
        );
    }

    @Override
    public DrawingModelDocumentVO getDrawingModelDocumentInfo(Long id) {
        return baseMapper.getDrawingModelDocumentInfo(id);
    }

    @Override
    public StorageModelQuantityVO storageModelQuantity() {
        return baseMapper.storageModelQuantity();
    }

    @Override
    public List<DrawingModelDocumentVO> downloadRankings(Integer rowsNumber) {
        return baseMapper.downloadRankings(rowsNumber);
    }

    @Override
    public void addDownloadsNumber(Long id) {
        DtsDrawingModelDocument drawingModelDocument = baseMapper.selectById(id);
        Integer downloadsNumber = drawingModelDocument.getDownloadsNumber() + 1;
        super.update(new UpdateWrapper<DtsDrawingModelDocument>().lambda()
                .set(DtsDrawingModelDocument::getDownloadsNumber, downloadsNumber)
                .eq(DtsDrawingModelDocument::getId, id)
        );
    }

    @Override
    public RegionDownloadsUploadsVO regionDownloadsUploads(String regionName) {
        List<String> timeList = new ArrayList<>();
        SimpleDateFormat toYearDateFormat = new SimpleDateFormat(DateUtils.YYYY);
        for (int month = 1; month <= 12; month++) {
            //用年月组合（yyyy-MM）去统计全年12个月份的数据
            String time = toYearDateFormat.format(new Date()) + StrUtil.DASHED + String.format("%02d", month);
            timeList.add(time);
        }
        DtsDrawingModelRegion drawingModelRegion = drawingModelRegionService.getOne(new QueryWrapper<DtsDrawingModelRegion>().lambda().eq(DtsDrawingModelRegion::getRegionName, regionName));
        List<Integer> downloads = baseMapper.regionDownloadsNum(drawingModelRegion.getId(), timeList);
        List<Integer> uploads = baseMapper.uploadsNum(drawingModelRegion.getId(), timeList);
        List<Integer> total = baseMapper.totalNum(drawingModelRegion.getId(), timeList);
        return RegionDownloadsUploadsVO.builder()
                .downloads(downloads)
                .uploads(uploads)
                .total(total)
                .build();
    }

}
